package msi.gama.display.java3d.renderer;

import java.awt.Color;
import java.awt.GraphicsConfiguration;
import java.util.HashMap;
import java.util.Map;

import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.vecmath.Color3f;
import javax.vecmath.Vector3f;

import msi.gama.display.java3d.input.InputProcessing;
import msi.gama.display.java3d.renderingObject.RenderingObject;
import msi.gama.display.java3d.scenegraph.J3DSceneGraph;
import msi.gama.metamodel.agent.IAgent;
import msi.gama.metamodel.shape.ILocation;
import msi.gama.metamodel.shape.IShape;

import com.sun.j3d.utils.universe.SimpleUniverse;

/**
 * minhvv, p18, IFI, TPE 01/2014 - 07/2014
 */

public class J3DRenderer {
	private static final int MAX_FRAME_RATE = 60;

	private static Canvas3D canvas3D = null;
	private static boolean sceneGraphReday = false;
	private static J3DSceneGraph sceneGraphHandler = new J3DSceneGraph();

	public static boolean isSceneGraphReady() {
		return true == sceneGraphReday;
	}

	private static HashMap<String, RenderingObject> renderingAgents =
			new HashMap<String, RenderingObject>();

	public static boolean isRenderingSurfaceCreated() {
		return null != canvas3D;
	}

	public static Canvas3D createRenderingSurface() {
		GraphicsConfiguration config =
				SimpleUniverse.getPreferredConfiguration();
		canvas3D = new Canvas3D(config);

		return canvas3D;
	}

	public static void createSceneGraphEnvironment() {
		SimpleUniverse universe = new SimpleUniverse(canvas3D);
		universe.getViewingPlatform().setNominalViewingTransform();
		universe.getViewer().getView()
				.setMinimumFrameCycleTime(1000 / MAX_FRAME_RATE);

		BranchGroup mainBranchGroup = sceneGraphHandler.createSceneGraph();
		universe.addBranchGraph(mainBranchGroup);

		InputProcessing.startListening();

		sceneGraphReday = true;
	}

	public static void renderGeometry(IAgent agent, IShape geometry,
			Color color, boolean fill, Color border, boolean rounded) {

		String agentName = agent.getName();
		boolean isAgentDead = agent.dead();
		Color3f fillColor = new Color3f(color);
		Color3f borderColor = new Color3f(border);

		// FIXME minhvv get environment size
		float envSize = 50.0f;

		ILocation loc = geometry.getLocation();
		Vector3f position = new Vector3f(
				(float) loc.getX() / envSize,
				(float) loc.getY() / envSize,
				(float) loc.getZ() / envSize);

		if (!renderingAgents.containsKey(agentName)) {
			if (isAgentDead) {
				return;
			}

			RenderingObject renderingObj = new RenderingObject(agentName, position,
					geometry, fillColor, borderColor, fill, rounded);
			renderingAgents.put(agentName, renderingObj);
			sceneGraphHandler.addRenderingObject(renderingObj);

		} else {
			RenderingObject currentRenderingObj = renderingAgents.get(agentName);

			if (isAgentDead) {
				currentRenderingObj.setObjectDead();
			}

			currentRenderingObj.updateDataOnEachFrame(agentName, position, geometry,
					fillColor, borderColor, fill, rounded);
		}
	}

	public static void beginRenderingOneFrame() {
	}

	public static void endRenderingOneFrame() {
		sceneGraphHandler.updateSceneAfterEachFrame();

		// TODO minhvv remove dead agent in renderinglist
	}

	private static void doDebug() {
		dump();
		sceneGraphHandler.dump();
	}

	/*
	 * FOR INPUT LISTENER
	 */

	public static void resetSceneRotate() {
		sceneGraphHandler.resetRotate();
	}

	public static void moveScreen(float offsetX, float offsetY) {
		System.out.println("MOVE SCREEN : " + offsetX + ", " + offsetY);
		sceneGraphHandler.moveScreen(offsetX, offsetY);
	}

	public static void dump() {
		for (Map.Entry<String, RenderingObject> entry : renderingAgents.entrySet()) {
			System.out.printf("%s : %s \n", entry.getKey(), entry.getValue());
		}
	}
}
